package com.dctp.ems.controller;

import com.dctp.common.controller.BaseController;
import com.dctp.common.core.RedisManager;
import com.dctp.common.db.UserDb;
import com.dctp.common.service.TradeService;
import com.dctp.common.service.UserRoleChainService;
import com.dctp.common.utils.DateUtil;
import com.dctp.common.utils.NumberUtil;
import com.dctp.common.utils.StringUtil;
import com.dctp.common.utils.UUIDUtil;
import com.dctp.common.vo.FundChangeType;
import com.dctp.common.vo.JsonResult;
import com.dctp.common.vo.PageResult;
import com.dctp.common.vo.RedisKey;
import com.dctp.ems.config.OpsLog;
import com.dctp.ems.interceptor.OpsLogInterceptor;
import com.jfinal.aop.Before;
import com.jfinal.core.NotAction;
import com.jfinal.core.Path;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.tx.Tx;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

import com.dctp.common.cache.RoleCache;
import com.dctp.common.cache.UserCache;

/**
 * 用户管理
 *
 * basePath: /user
 */
@Path("/user")
public class UserController extends BaseController {

    /**
     * GET /user/list
     * <p>
     * 分页查询用户（支持 create_time 范围）
     * </p>
     */
    public void list() {
        int page = getInt("currentPage", 1);
        int pageSize = getInt("pageSize", 10);
        String email = getPara("email", "");
        String nickName = getPara("nick_name", "");
        String status = getPara("status", "");
        String createTimeStart = getPara("start_time", "");
        String createTimeEnd = getPara("end_time", "");
        Integer roleId = getParaToInt("role_id");

        StringBuilder where = new StringBuilder(" WHERE id !=1  ");
        List<Object> params = new ArrayList<>();
        if (StrKit.notBlank(email)) {
            where.append(" AND email LIKE ? ");
            params.add('%' + email + '%');
        }

        if (null != roleId) {
            where.append(" AND role_id = ? ");
            params.add(roleId);
        }

        if (StrKit.notBlank(nickName)) {
            where.append(" AND nick_name LIKE ? ");
            params.add('%' + nickName + '%');
        }

        String stags = getPara("tags");
        if (StrKit.notBlank(stags)) {
            where.append(" AND tags LIKE ? ");
            params.add('%' + stags + '%');
        }

        String clientVersion = getPara("client_version");
        if (StrKit.notBlank(clientVersion)) {
            where.append(" AND client_version = ? ");
            params.add(clientVersion);
        }

        String clientEnv = getPara("client_env");
        if (StrKit.notBlank(clientEnv)) {
            where.append(" AND client_env = ? ");
            params.add(clientEnv);
        }

        if (StrKit.notBlank(status)) {
            where.append(" AND status = ? ");
            params.add(status);
        }
        if (StrKit.notBlank(createTimeStart)) {
            where.append(" AND create_time >= ? ");
            params.add(DateUtil.parse(createTimeStart));
        }
        if (StrKit.notBlank(createTimeEnd)) {
            where.append(" AND create_time <= ? ");
            params.add(DateUtil.parse(createTimeEnd));
        }

        Long queryId = getParaToLong("user_id");
        if (queryId != null) {
            where.append(" AND id = ? ");
            params.add(queryId);
        }

        String filterField = getFilterField();
        if (filterField != null) {
            where.append(" AND ").append(filterField).append(" = ?");
            params.add(getRequestUser().getLong("user_id"));
        }

        String roleKey = getPara("roleKey");
        Long roleUserId = getParaToLong("roleUserId");
        if (StringUtil.isNotEmpty(roleKey) && null != roleUserId) {
            where.append(" AND ").append(roleKey).append(" = ?");
            params.add(roleUserId);
        }

        var p = Db.paginate(page, pageSize,
                "SELECT *, '' AS role_name ",
                "FROM dctp_user" + where + " ORDER BY id DESC",
                params.toArray());
        // 填充 role_name 和 parent
        List<Record> list = p.getList();
        for (Record rec : list) {
            rec.remove("password"); // 移除敏感字段
            rec.remove("pay_password");
            rec.remove("token");

            Long userId = rec.getLong("id");
            String sybBalance = RedisManager.getInstance().get(String.format(RedisKey.USER_SYB_BALANCE, userId));
            if (StrKit.notBlank(sybBalance)) {
                rec.put("sybBalance", sybBalance);
            }else {
                rec.put("sybBalance", "0");
            }
            Long roleIdVal = rec.getLong("role_id");
            String roleName = "";
            if (roleIdVal != null) {
                Record role = RoleCache.getById(roleIdVal);
                if (role != null) {
                    roleName = role.getStr("name");
                }
            }
            rec.set("role_name", roleName);
            // 填充 parent
            Long parentId = rec.getLong("parent_id");
            if (parentId != null && parentId != 0L) {
                rec.set("parent", UserCache.getBasic(parentId));  
            }

            String tags = rec.getStr("tags");
            if (StringUtil.isNotEmpty(tags)) {
                rec.set("tags", tags.split(","));
            }

            String key = getGroupByIdKey();
            Long orgId = rec.getLong(key);
            if (null != orgId) {
                Record showInfo = UserCache.getShowInfo(orgId);
                rec.set("orgInfo", showInfo);
            }
        }
        renderJson(JsonResult.successWithData(
            new PageResult<>(list, p.getTotalRow(), pageSize, page)
        ));
    }

    /**
     * POST /user/register
     * <p>
     * 注册新用户（带推广码链、唯一性校验等）
     * </p>
     */
    @Before(Tx.class)
    public void add() {

        Record body = jsonBody();
        String email = body.getStr("email");

        Record user = UserDb.findByEmail(email);
        if (null != user) {
            renderJson(JsonResult.fail("USER_EXIST").show("用户已存在"));
            return;
        }

        Long roleId = body.getLong("role_id");

        String password = body.getStr("login_password");
        String token = UUIDUtil.random32();
        // 保证推广码唯一
        Integer promoteCode = NumberUtil.random8Digits();
        Long uId = UserDb.findIdByPromoteCode(promoteCode);
        while (null != uId) {
            promoteCode = NumberUtil.random8Digits();
            uId = UserDb.findIdByPromoteCode(promoteCode);
        }

        Long parentId = body.getLong("parent_id");
        Long bottomRoleUserId = null;
        Long middleRoleUserId = null;
        Long topRoleUserId = null;
        if (parentId != 0L) {
            UserRoleChainService.UserRoleChain chain = UserRoleChainService.findRoleChain(parentId);
            bottomRoleUserId = chain.bottomRoleUserId;
            middleRoleUserId = chain.middleRoleUserId;
            topRoleUserId = chain.topRoleUserId;
        }
        Record r = new Record();
        r.set("email", email)
                .set("nick_name", String.format("Trader%s", NumberUtil.random6Digits()))
                .set("login_password", password)
                .set("status", 1)
                .set("create_time", DateUtil.now())
                .set("promote_code", promoteCode)
                .set("parent_id", parentId)
                .set("token", token)
                .set("role_id", roleId)
                .set("bottom_role_user_id", bottomRoleUserId)
                .set("middle_role_user_id", middleRoleUserId)
                .set("top_role_user_id", topRoleUserId);

        if (!Db.save("dctp_user", r)) {
            throw new RuntimeException("REGISTER_FAIL");
        }

        this.saveUserRole(r);
        renderJson(JsonResult.successWithData(token));
    }

    /**
     * POST /user/update/:id
     * <p>
     * 更新用户信息（排除敏感字段，邮箱/账号唯一校验，父级变动自动级联）
     * </p>
     */
    @Before({Tx.class, OpsLogInterceptor.class})
    @OpsLog(module = "用户管理",
            action = "更新用户",
            table = "dctp_user",
            fields = {"parent_id", "role_id", "balance","status","dead_line"})
    public void update() {
        Long id = getParaToLong(0);
        if (id == null) {
            renderJson(JsonResult.failWithMessage("参数缺失"));
            return;
        }
        Record body = jsonBody();
        if (body.getColumns().isEmpty()) {
            renderJson(JsonResult.failWithMessage("无有效字段"));
            return;
        }

        // 排除敏感字段
        body.remove("balance");
        body.remove("pay_password");
        body.remove("token");
        body.remove("promote_code");

        // 取原始用户数据
        Record oldUser = Db.findById("dctp_user", id);
        if (oldUser == null) {
            renderJson(JsonResult.failWithMessage("用户不存在"));
            return;
        }

        // 校验邮箱唯一
        String newEmail = body.getStr("email");
        if (StrKit.notBlank(newEmail) && !newEmail.equals(oldUser.getStr("email"))) {
            Long exist = Db.queryLong("SELECT id FROM dctp_user WHERE email=? AND id<>?", newEmail, id);
            if (exist != null) {
                renderJson(JsonResult.failWithMessage("邮箱已被占用"));
                return;
            }
        }

        // 校验 login_account（如果存在该字段）
        String newLoginAccount = body.getStr("login_account");
        if (StrKit.notBlank(newLoginAccount)) {
            String oldLoginAccount = oldUser.getStr("login_account");
            if (!newLoginAccount.equals(oldLoginAccount)) {
                Long exist = Db.queryLong("SELECT id FROM dctp_user WHERE login_account=? AND id<>?", newLoginAccount,
                        id);
                if (exist != null) {
                    renderJson(JsonResult.failWithMessage("账号已被占用"));
                    return;
                }
            }
        }

        // 检查 parent_id 是否变化
        Long newParentId = body.getLong("parent_id");
        if (newParentId != null && !newParentId.equals(oldUser.getLong("parent_id"))) {
            // 重新计算角色链
            Long parentId = newParentId;
            Long bottomRoleUserId = null, middleRoleUserId = null, topRoleUserId = null;
            if (parentId != 0L) {
                UserRoleChainService.UserRoleChain chain = UserRoleChainService.findRoleChain(parentId);
                bottomRoleUserId = chain.bottomRoleUserId;
                middleRoleUserId = chain.middleRoleUserId;
                topRoleUserId = chain.topRoleUserId;
            }
            body.set("bottom_role_user_id", bottomRoleUserId)
                    .set("middle_role_user_id", middleRoleUserId)
                    .set("top_role_user_id", topRoleUserId);
        }
        //
        Long newRoleId = body.getLong("role_id");
        Long oldRoleId = oldUser.getLong("role_id");

        if (newRoleId != null &&  oldRoleId != null && newRoleId.compareTo(oldRoleId) != 0) {
            //设置有效期
            LocalDateTime now = LocalDateTime.now();
            body.set("dead_line",newRoleId > 1 ? now.plusYears(1) : null);
        }


        body.set("id", id)
                .set("update_time", DateUtil.now());
        boolean updated = Db.update("dctp_user", body);
        if (!updated) {
            renderJson(JsonResult.failWithMessage("更新失败或记录不存在"));
            return;
        }

        //更改角色
        this.saveUserRole(body);
        //删除缓存
        UserCache.delete(id);
        setAttr("oldRecord",oldUser);//用于日志记录
        renderJson(JsonResult.success());
    }

    @NotAction
    private void saveUserRole(Record user) {

        Long userId = user.getLong("id");
        Long roleId = user.getLong("role_id");
        if (roleId == 1) {
            //普通用户不保存
            return;
        }
        Long id = Db.queryLong("select id from dctp_role_recharge where user_id = ? and role_id = ? and audit_status = 1 ",
                userId, roleId);
        if (null != id) {
            return;
        }

        Long bottomRoleUserId = null;
        Long middleRoleUserId = null;
        Long topRoleUserId = null;
        Long parentId = user.getLong("parent_id");
        if (null != parentId && parentId != 0L) {
            UserRoleChainService.UserRoleChain chain = UserRoleChainService.findRoleChain(parentId);
            bottomRoleUserId = chain.bottomRoleUserId;
            middleRoleUserId = chain.middleRoleUserId;
            topRoleUserId = chain.topRoleUserId;
        }


        Record recharge = new Record()
                .set("user_id", userId)
                .set("amount", 0)
                .set("role_id", roleId)
                .set("chain_type", "")
                .set("deposit_address", "")
                .set("voucher_img", "")
                .set("block_status", 0)
                .set("audit_status", 0)
                .set("status", 1)
                .set("audit_status",1)
                .set("audit_time", DateUtil.now())
                .set("remark","后台更新")
                .set("create_time", DateUtil.now())
                .set("update_time", DateUtil.now())
                .set("parent_id",parentId)
                .set("bottom_role_user_id", bottomRoleUserId)
                .set("middle_role_user_id", middleRoleUserId)
                .set("top_role_user_id", topRoleUserId);
        Db.save("dctp_role_recharge", recharge);

        String filed = getRoleField(roleId);
        if (StringUtil.isNotEmpty(filed)) {
            String sql = "update dctp_user set " + filed + " = ? " +
                    "where parent_id = ? ";
            Db.update(sql, userId, userId );
        }
    }

    /**
     * POST /user/delete/:id
     * <p>
     * 删除用户
     * </p>
     */
    @Before(Tx.class)
    public void delete() {
        Long id = getParaToLong(0);
        if (id == null) {
            renderJson(JsonResult.failWithMessage("参数缺失"));
            return;
        }
        boolean success = Db.deleteById("dctp_user", id);
        if (!success) {
            renderJson(JsonResult.failWithMessage("用户不存在或删除失败"));
        } else {
            renderJson(JsonResult.success());
        }
    }

    /**
     * GET /user/all
     * <p>
     * 获取所有启用状态的用户，支持关键字远程搜索
     * </p>
     */
    public void all() {
        String keyword = getPara("keyword", "").trim();
        StringBuilder sql = new StringBuilder("SELECT id, email, nick_name FROM dctp_user WHERE status = 1");
        List<Object> params = new ArrayList<>();
        if (StrKit.notBlank(keyword)) {
            sql.append(" AND (nick_name LIKE ? OR email LIKE ?)");
            params.add('%' + keyword + '%');
            params.add('%' + keyword + '%');
        }

        String roleKey = getPara("roleKey", "").trim();
        Integer roleId = null;
        if (StringUtil.isNotEmpty(roleKey)) {
            if ("top_role_user_id".equals(roleKey)) {
                roleId = 4;
            }else if ("middle_role_user_id".equals(roleKey)) {
                roleId = 3;
            }else  if ("bottom_role_user_id".equals(roleKey)) {
                roleId = 2;
            }
        }

        if (null != roleId) {
            sql.append(" AND role_id = ?");
            params.add(roleId);
        }

        sql.append(" ORDER BY id DESC LIMIT 30");
        List<Record> list = Db.find(sql.toString(), params.toArray());
        renderJson(JsonResult.successWithData(list));
    }

    /**
     * GET /user/relations/:id
     * 返回某个用户的递归上级链（parent_id链）
     */
    public void relations() {
        Long id = getParaToLong(0);
        if (id == null) {
            renderJson(JsonResult.failWithMessage("参数缺失"));
            return;
        }
        List<Map<String, Object>> chain = new ArrayList<>();
        Long currentId = id;
        Set<Long> visited = new HashSet<>(); // 防止死循环
        while (currentId != null && currentId != 0L && !visited.contains(currentId)) {
            Record user = Db.findById("dctp_user", currentId);
            if (user == null) break;
            Record basic = UserCache.getBasic(currentId);
            if (basic != null) {
               chain.add(basic.getColumns());
            }
            visited.add(currentId);
            currentId = user.getLong("parent_id");
        }
        renderJson(JsonResult.successWithData(chain));
    }


    @Before({Tx.class, OpsLogInterceptor.class})
    @OpsLog(module = "用户管理",
            action = "额度变更",
            table = "dctp_user",
            fields = {"balance"})
    public void updateBalance() {

        Long id = getParaToLong(0);
        Record body = jsonBody();
        String remark = body.getStr("remark");
        if (StringUtil.isEmpty(remark)) {
            renderJson(JsonResult.failWithMessage("请填写备注"));
            return;
        }

        Long userId = body.getLong("id");
        if (null == userId) {
            renderJson(JsonResult.failWithMessage("参数异常"));
            return;
        }

        Record user = Db.findById("dctp_user", userId);
        if (null == user) {
            renderJson(JsonResult.failWithMessage("用户不存在"));
            return;
        }

        Integer status = user.getInt("status");
        if (status == 0) {
            renderJson(JsonResult.failWithMessage("用户状态异常"));
            return;
        }

        BigDecimal amount = body.getBigDecimal("amount");
        if (amount == null || amount.compareTo(BigDecimal.ZERO) == 0) {
            renderJson(JsonResult.failWithMessage("金额不能为0或者不能为空"));
            return;
        }

        BigDecimal balance = user.getBigDecimal("balance");
        BigDecimal afterBalance = balance.add(amount);
        if (afterBalance.compareTo(BigDecimal.ZERO) < 0) {
            renderJson(JsonResult.failWithMessage("金额会导致用户余额为负数"));
            return;
        }

        int r = Db.update("update dctp_user set balance = balance + (?) where id = ?", amount, id);
        if (r != 1) {
            throw new RuntimeException("操作失败");
        }

        //增加资金流水
        TradeService.saveFundFlow(user,FundChangeType.EMS_OPS,balance,afterBalance,amount,0L,remark);

        body.set("balance", afterBalance);
        setAttr("oldRecord",user);
        renderJson(JsonResult.success());
    }


    @Before({Tx.class, OpsLogInterceptor.class})
    @OpsLog(module = "用户管理",
            action = "1:1额度",
            table = "dctp_user",
            fields = {"balance2"})
    public void updateBalance2() {

        Long id = getParaToLong(0);
        Record body = jsonBody();
        String remark = body.getStr("remark");
        if (StringUtil.isEmpty(remark)) {
            renderJson(JsonResult.failWithMessage("请填写备注"));
            return;
        }

        Long userId = body.getLong("id");
        if (null == userId) {
            renderJson(JsonResult.failWithMessage("参数异常"));
            return;
        }

        Record user = Db.findById("dctp_user", userId);
        if (null == user) {
            renderJson(JsonResult.failWithMessage("用户不存在"));
            return;
        }

        Integer status = user.getInt("status");
        if (status == 0) {
            renderJson(JsonResult.failWithMessage("用户状态异常"));
            return;
        }

        BigDecimal amount = body.getBigDecimal("amount");
        if (amount == null || amount.compareTo(BigDecimal.ZERO) == 0) {
            renderJson(JsonResult.failWithMessage("金额不能为0或者不能为空"));
            return;
        }

        BigDecimal balance = user.getBigDecimal("balance");
        BigDecimal afterBalance = balance.add(amount);
        if (afterBalance.compareTo(BigDecimal.ZERO) < 0) {
            renderJson(JsonResult.failWithMessage("金额会导致用户余额为负数"));
            return;
        }

        BigDecimal balance2 = user.getBigDecimal("balance2");
        BigDecimal afterBalance2 = balance2.add(amount);

        int r = Db.update("update dctp_user set balance = balance + (?),balance2 = balance2 + (?) where id = ?", amount,amount, id);
        if (r != 1) {
            throw new RuntimeException("操作失败");
        }

        //增加资金流水
        TradeService.saveFundFlow(user,FundChangeType.EMS_OPS2,balance,afterBalance,amount,0L,remark);

        body.set("balance2", afterBalance2);
        setAttr("oldRecord",user);
        renderJson(JsonResult.success());
    }
}
